#include "ip.h"
#include "etharp.h"
#include "ip_addr.h"

/*
**IP校验和
*/
uint16_t 
ip_checksum(uint8_t *buff,uint8_t size){
  /*置零*/
  /*转换为char *类型*/
  uint8_t  *temp_hdr =buff;
  /*高低*/
  uint32_t temp_sum =0;
  uint32_t sum=0;
  /*求和*/
  for(uint8_t i=0;i<size;i+=2){
    temp_sum +=temp_hdr[i] << 8; 
    temp_sum +=temp_hdr[i+1];
    sum +=temp_sum;
    temp_sum=0;       
  }
  /*高16位和低16位相加*/
  temp_sum =sum&0x0000FFFF;
  temp_sum +=(sum>>16)&0xFFFF;
  if(temp_sum&0xffff0000)
  {//表示有进位
    temp_sum++;
  }
  return ((uint16_t)(~((temp_sum)&0xffff)));
}
/*
**IP层数据输出函数
*/
void 
ip_output(struct netif *netif,struct pbuf *p,ip_addr_t *addr)
{
  struct netif *lnetif =netif;
  
  uint8_t ip_hdr[20];
  Pack_ip_hdr    *iphdr=(Pack_ip_hdr    *)ip_hdr;
  static uint16_t ip_idenfication=0;
  /*版本号以及首部长度*/
  iphdr->vhl =netif->iphdrlen|Version_ip;
  
  iphdr->tos =0;
  /*IP标识符*/
  iphdr->ipid=ip_idenfication++;
  /**/
  iphdr->ipoffset = 0;
  /*生存时间*/
  iphdr->ttl =0x40;
  /*源Ip*/
  iphdr->srcipaddr=htonl(netif->lacotip_addr.addr);
  /*目的地址*/
  iphdr->destipaddr=htonl(addr->addr);
  /*是什么样的数据类型*/
  switch(lnetif->flags){
  case IP_PROTO_UDP:
    /*协议类型*/
    iphdr->protocol =IP_PROTO_UDP;
    /*Ip数据包长度，包括报文*/
    iphdr->tot_len=htons(p->len+(netif->iphdrlen*4)+udphdr_len);
    break;
  case IP_PROTO_TCP:
    /*协议类型*/
    iphdr->protocol =IP_PROTO_TCP;
    /*Ip数据包长度，包括报文*/
    iphdr->tot_len=htons(p->len+(netif->iphdrlen*4)+(netif->tpcb->tcp_hdrlen*4));   
    break;
  default:
    break;
  }
  /*首部校验和*/
  iphdr->ipchksum=htons(ip_checksum((uint8_t *)iphdr,netif->iphdrlen*4));
  /*拷贝数据*/
  memcpy((uint8_t *)p->payload+SIZEOF_ETH_HDR,ip_hdr,sizeof(Pack_ip_hdr));
  /*传给ETH层*/
  lnetif->flags=ETHTYPE_IP;
  
  eth_output(netif,p);
  
  return ;
}

/*
**IP层数据输入函数
*/
void
ip_input(struct netif *netif,struct pbuf *p)
{
  struct netif   *lnetif;
  struct eth_hdr *ethhdr;
  Pack_ip_hdr    *iphdr;
  Pack_udp_hdr  *udphdr;
  Pack_tcp_hdr   *tcphdr;
  ip_addr_t   srcipaddr;
  uint8_t type;
  uint16_t iphdr_sum=0;
  /*eth报文*/
  ethhdr = (struct eth_hdr *)p->payload;
  /*ip报文*/
  iphdr =(Pack_ip_hdr*)((uint8_t *)ethhdr+SIZEOF_ETH_HDR);
  
  iphdr_sum =htons(iphdr->ipchksum);
  /*协议类型*/
  type=iphdr->protocol;
  /*字节序转换*/
  srcipaddr.addr=htonl(iphdr->destipaddr);
  /*首部长度*/
  netif->iphdrlen=IPH_HL(iphdr);
  
  iphdr->ipchksum = 0;
  /*ip校验和*/
  if(ip_checksum((uint8_t  *)iphdr,netif->iphdrlen*4)!=iphdr_sum)
    return ;      /*校验和不对*/
  
  for(lnetif=netif;lnetif !=NULL;lnetif=lnetif->next){
    /*过滤IP*//*这里没有做到像lwip那样与网关，以及掩码取配合识别IP,所以在IP
    识别上可能会有些漏洞，这里只涉及两个协议，ip过滤可能不安全，以及过滤的冗余性
    */
    if(lnetif->lacotip_addr.addr==srcipaddr.addr||
       //artNet的广播
       AerNet_BROADCAST==srcipaddr.addr||
         //artNet的广播
         AerNet_BROADCAST1==srcipaddr.addr||
           //全网广播
           IPADDR_BROADCAST==srcipaddr.addr||
             ip_addr_broadcast(&srcipaddr)){
               switch(type){
               case IP_PROTO_UDP:
                 udphdr=(Pack_udp_hdr *)((uint8_t *)iphdr+(netif->iphdrlen*4));
                 /*UDP数据解析*/
                 if(htons(udphdr->nDestPort)==
                    lnetif->upcb->local_port){
                      /*保存本地IP首部的长度*/
                      lnetif->iphdrlen=IPH_HL(iphdr);
                      /*保存远端地址*/
                      lnetif->remotip_addr.addr=htonl(iphdr->srcipaddr);
                      p->hdr_len=(14/*ETH首部，一般情况固定不变*/+(netif->iphdrlen)*4+UDP_HLEN);
                      /*IP数据包的长度*/
                      lnetif->ip_datalen=(htons(iphdr->tot_len)-lnetif->iphdrlen*4);
                      /*数据送至传输层*/
                      udp_input(lnetif,p);
                      
                      break;
                    }
                 
                 break;
               case IP_PROTO_TCP:
                 tcphdr=(Pack_tcp_hdr *)((uint8_t *)iphdr+(netif->iphdrlen*4));
                 
                 if(htons(tcphdr->dest)==
                    lnetif->tpcb->local_port){               
                      /*保存本地IP首部的长度*/
                      lnetif->iphdrlen=IPH_HL(iphdr);
                      /*保存远端地址*/
                      lnetif->remotip_addr.addr=htonl(iphdr->srcipaddr);
                      p->hdr_len=(14/*ETH首部，一般情况固定不变*/+(netif->iphdrlen)*4);
                      /*IP数据包的长度*/
                      lnetif->ip_datalen=(htons(iphdr->tot_len)-lnetif->iphdrlen*4);
                      /*传至TCP数据解析*/
                      tcp_input(lnetif,p);
                      
                      break;
                    }
                 break;
               default:
                 break;
               }
             }
  }
  p->payload=myfree(SRAM_IN,p->payload);
  p=(struct pbuf *)myfree(SRAM_IN,p);//释放内存
}
